#include <rtthread.h>
#include <rtdevice.h>
#include <unistd.h>

#include <fal.h>
#include <dfs.h>
#include <dfs_fs.h>
#include <dfs_file.h>
#include "config_api.h"
#include "boot_api.h"

#define DBG_ENALE
#define DBG_SECTION_NAME    "fs_mount"
#define DBG_LEVEL           DBG_INFO
#include <rtdbg.h>

#define ROOT_PARTITION_NAME     "root"
#define RESERVE_PARTITION_NAME  "reserve"
#define LOGS_PARTITION_NAME     "logs"
#define LOGS_PATH               "/logs"

static struct rt_device *root_fs_dev;
static struct rt_device *reserve_fs_dev;
static struct rt_device *logs_fs_dev;

int filesystem_mount_init(void)
{
    int fd;
    rt_err_t ret;

    fal_init();

    // create mtd nor flash device, root partiton
    root_fs_dev = fal_mtd_nor_device_create(ROOT_PARTITION_NAME);
    if (root_fs_dev == NULL)
    {
        LOG_E("Can't create a mtd device on '%s' partition.", ROOT_PARTITION_NAME);
        return -RT_ERROR;
    }
    else
    {
        LOG_D("Create a mtd device on %s partition successful.", ROOT_PARTITION_NAME);
    }

    // reserve partition
    reserve_fs_dev = fal_mtd_nor_device_create(RESERVE_PARTITION_NAME);
    if (reserve_fs_dev == NULL)
    {
        LOG_E("Can't create a mtd device on '%s' partition.", RESERVE_PARTITION_NAME);
        return -RT_ERROR;
    }
    else
    {
        LOG_D("Create a mtd device on the %s partition successful.", RESERVE_PARTITION_NAME);
    }

    logs_fs_dev = fal_mtd_nor_device_create(LOGS_PARTITION_NAME);
    if (logs_fs_dev == NULL)
    {
        LOG_E("Can't create a mtd device on '%s' partition.", LOGS_PARTITION_NAME);
        return -RT_ERROR;
    }
    else
    {
        LOG_I("Create a mtd device on the %s partition successful.", LOGS_PARTITION_NAME);
    }

    // mount root
    if (dfs_mount(root_fs_dev->parent.name, "/", "lfs", 0, 0))
    {
        LOG_I("mount root partition on / error, try to mkfs.");

        if (dfs_mkfs("lfs", root_fs_dev->parent.name))
        {
            LOG_E("mkfs root partition error, exit.");
            return -RT_ERROR;
        }

        LOG_I("mkfs root partiton ok, try mount root again.");

        if (dfs_mount(root_fs_dev->parent.name, "/", "lfs", 0, 0))
        {
            LOG_E("mount root again error, exit.");
            return -RT_ERROR;
        }
    }

    LOG_I("mount root partition on / success.");

    // check dir /reserve if exist, and create it
    fd = open("/reserve", O_DIRECTORY | O_CREAT);
    if (fd < 0)
    {
        if (rt_get_errno() != -EEXIST)
        {
            LOG_E("dir /reserve open&create error, exit");
            return -RT_ERROR;
        }
        LOG_D("dir /reserve already exist");
    }
    else
    {
        LOG_I("create dir /reserve success");
        close(fd);
    }

    // mount reserve
    if (dfs_mount(reserve_fs_dev->parent.name, "/reserve", "lfs", 0, 0))
    {
        LOG_I("mount reserve partition on /reserve error, try to mkfs.");

        if (dfs_mkfs("lfs", reserve_fs_dev->parent.name))
        {
            LOG_E("mkfs reserve partition error, exit.");
            return -RT_ERROR;
        }

        LOG_I("mkfs reserve partiton ok, try mount reserve again.");

        if (dfs_mount(reserve_fs_dev->parent.name, "/reserve", "lfs", 0, 0))
        {
            LOG_E("mount reserve again error, exit.");
            return -RT_ERROR;
        }
    }

    LOG_I("mount reserve partition on /reserve success");

    LOG_I("filesystem load success");

    fd = open(LOGS_PATH, O_DIRECTORY | O_CREAT);
    if (fd < 0)
    {
        if (rt_get_errno() != -EEXIST)
        {
            LOG_E("dir %s open&create error, exit", LOGS_PATH);
            return -RT_ERROR;
        }
        LOG_D("dir %s already exist", LOGS_PATH);
    }
    else
    {
        LOG_I("create dir %s success", LOGS_PATH);
        close(fd);
    }

    char *fs_type = "lfs";
    if (dfs_mount(logs_fs_dev->parent.name, LOGS_PATH, fs_type, 0, 0))
    {
        LOG_W("mount %s partition on %s error, try to mkfs.", LOGS_PARTITION_NAME, LOGS_PATH);

        if (dfs_mkfs(fs_type, logs_fs_dev->parent.name))
        {
            LOG_E("mkfs %s partition error, exit.", LOGS_PARTITION_NAME);
            return -RT_ERROR;
        }

        LOG_I("mkfs %s partiton ok, try mount %s again.", LOGS_PARTITION_NAME, LOGS_PARTITION_NAME);

        if (dfs_mount(logs_fs_dev->parent.name, LOGS_PATH, fs_type, 0, 0))
        {
            LOG_E("mount %s again error, exit.", LOGS_PARTITION_NAME);
            return -RT_ERROR;
        }
    }

    LOG_I("mount %s partition on %s success", LOGS_PARTITION_NAME, LOGS_PATH);

    LOG_I("norflash load success");
    return RT_EOK;
}

static int file_data_mount_init(void)
{
    if (filesystem_mount_init())
    {
        LOG_E("filesystem_mount_init error");
    }
    else
    {
        // 初始化静态数据
        uc_static_data_init();
        uc_boot_cfg_init();
    }
    return 0;
}

INIT_ENV_EXPORT(file_data_mount_init);
